package ${domain}.module.wsys.mgr;

import ${domain}.frame.auth.Token;
import ${domain}.frame.base.ErrorType;
import ${domain}.frame.utils.IDgenerator;
import ${domain}.frame.utils.RandomUtil;
import ${domain}.frame.utils.ValidationUtil;
import ${domain}.module.wsys.ent.Sequence;
import ${domain}.module.wsys.mpr.SequenceMapper;
import ${domain}.module.wsys.req.SequenceFindRequest;
import ${domain}.module.wsys.req.SequenceNextRequest;
import ${domain}.module.wsys.req.SequenceRamHexRequest;
import ${domain}.module.wsys.rsp.SequenceFindResponse;
import ${domain}.module.wsys.rsp.SequenceNextResponse;
import ${domain}.module.wsys.rsp.SequenceRamHexResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * SEQUENCE - 序列
 *
 * @author wangbing
 * @version 0.0.1
 * @since 2020-06-25
 */
@Transactional
@Service
public class SequenceManagerImpl implements SequenceManager {

    @Autowired
    private SequenceMapper sequenceMapper;

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

    /**
     * 查询
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    @Transactional(readOnly = true)
    public SequenceFindResponse find(SequenceFindRequest request, Token token) {
        SequenceFindResponse response = new SequenceFindResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        if (request.getPageSize() != 0) {
            PageHelper.startPage(request.getPageNumber(), request.getPageSize());
        }
        if (StringUtil.isNotEmpty(request.getSortKey())) {
            PageHelper.orderBy(request.getSortKey() + " " + request.getSortType());
        }
        PageInfo<Sequence> pageInfo = new PageInfo<>(sequenceMapper.find(request, token));

        response.setResult(pageInfo.getList());
        response.setTotalCount(pageInfo.getTotal());

        return response;
    }

    /**
     * 获得对象
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    @Transactional(readOnly = true)
    public SequenceNextResponse next(SequenceNextRequest request, Token token) {
        SequenceNextResponse response = new SequenceNextResponse();

        int value = 0;
        String year = null;
        String month = null;
        String date = null;
        String format = dateFormat.format(new Date());
        if (request.getByYear()) year = format.substring(0, 4);
        if (request.getByMonth()) month = format.substring(4, 6);
        if (request.getByDate()) date = format.substring(6, 8);

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        int retryCount = 100;
        do {
            // 首先查询是否已经开始的序列
            SequenceFindRequest sequenceFindRequest = new SequenceFindRequest();
            sequenceFindRequest.setSeqName(request.getSeqName());
            sequenceFindRequest.setYear(year);
            sequenceFindRequest.setMonth(month);
            sequenceFindRequest.setDate(date);
            SequenceFindResponse sequenceFindResponse = this.find(sequenceFindRequest, token);
            if (sequenceFindResponse.getTotalCount() > 0) {
                Sequence sequence = sequenceFindResponse.getResult().get(0);
                // 检查流水是否达到上限,达到最大值或理论最大值
                if (sequence.getNextValue() > request.getMaxValue()) {
                    response.addError(ErrorType.BUSINESS_ERROR, "流水已达上限，请等待下个周期!");
                    return response;
                }
                // 更新下一个流水号
                sequence.setNextValue(sequence.getNextValue() + request.getSeqStep());
                long update = sequenceMapper.update(sequence, token);
                if (update == 1) {
                    value = sequence.getNextValue() - request.getSeqStep();
                    break;
                }
            } else {// 未开始的序列
                Sequence forCreate = new Sequence();
                long id = IDgenerator.nextId();
                forCreate.setId(id);
                forCreate.setSeqName(request.getSeqName());
                forCreate.setSeqNote(request.getSeqNote());
                forCreate.setYear(year);
                forCreate.setMonth(month);
                forCreate.setDate(date);
                forCreate.setNextValue(request.getMinValue() + request.getSeqStep());
                long insert = sequenceMapper.insert(forCreate, token);
                if (insert == 1) {
                    value = request.getMinValue();
                    break;
                }
            }
            retryCount--;
        } while (value <= 0 && retryCount > 0);

        try {
            TransactionAspectSupport.currentTransactionStatus().flush();
        } catch (Exception e) {
            response.addError(ErrorType.BUSINESS_ERROR, "生成序列失败，请稍后再试!");
            return response;
        }

        response.setSequence(String.format(Locale.CHINA, "%s%s%s%s%0" + String.valueOf(request.getMaxValue()).length() + "d",
                request.getSeqPrefix(),
                year == null ? "" : year,
                month == null ? "" : month,
                date == null ? "" : date,
                value));
        return response;
    }

    /**
     * 获得HEX序列
     *
     * @param request 请求对象
     * @param token   令牌
     * @return
     */
    @Override
    public SequenceRamHexResponse ramHex(SequenceRamHexRequest request, Token token) {
        SequenceRamHexResponse response = new SequenceRamHexResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        String sequence = RandomUtil.getString("0123456789abcdef", request.getSize());
        response.setSequence(sequence);
        if (request.isUpperCase()) {
            response.setSequence(response.getSequence().toUpperCase());
        }
        if (StringUtil.isNotEmpty(request.getPrefix())) {
            response.setSequence(request.getPrefix() + response.getSequence());
        }
        if (StringUtil.isNotEmpty(request.getSuffix())) {
            response.setSequence(response.getSequence() + request.getSuffix());
        }

        return response;
    }
}
